//code 2 threads:tid lwp g_val detach
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
using namespace std;
//添加__thread 使得线程保存并访问自己局部存储的 g_int
__thread int g_int = 100;
void *thread_todo_func(void *arg)
{

    // 可以获取调用执行流的线程id
    // 线程id就是共享区内,库维护的线程结构体的地址,里面保存线程的栈结构,相关属性和局部存储
    pthread_t tid = pthread_self();
    string thread_name(static_cast<char *>(arg));
    // 线程分离, 分离后不再关心子线程的退出情况,并且自动释放资源,但还是要保证先于主线程退出
    // 更推荐于主线程去分离,这样能确保主线程如果join会失败,不会因为执行流调度顺序不确定导致先join再执行到detach
    // pthread_detach(tid);

    int n = 5;
    while (n--)
    {
        cout << thread_name << " 运行中... "
             << " tid: " << (void *)tid
             << " LWP: " << syscall(SYS_gettid) << " g_int: " << g_int++ << " &g_int: " << &g_int << endl;
        sleep(1);
    }
    //通过void*来返回线程退出码,通过以下方式,退出码会通过join里的输出型参数传递
    //线程退出的方式1 return
    // return (void*)999;
    //线程退出的方式2 pthread_exit
    pthread_exit((void *)999);
    //线程的退出方式3,主线程调用 pthread_cancel
    //线程退出方式4,代码执行完毕,自动返回0
}

int main()
{
    pthread_t tid_1;
    pthread_t tid_2;
    pthread_t tid_3;

    if (!pthread_create(&tid_1, nullptr, thread_todo_func, (void *)"thread_1") &&
        !pthread_create(&tid_2, nullptr, thread_todo_func, (void *)"thread_2") &&
        !pthread_create(&tid_3, nullptr, thread_todo_func, (void *)"thread_3"))
        cout << "创建线程成功!" << endl;
    else
        return errno;
    

    //1. 立即分离,2.延后分离(确保线程活着)
    pthread_detach(tid_1);
    pthread_detach(tid_2);
    pthread_detach(tid_3);
    cout<<"线程分离成功"<<endl;
    cout<<"......"<<endl;
    //joinable和detch不可同时满足 detch了就不能join 
    //不同于设置了信号忽略的进程等待
    //若detch后主线程调用join,会杀掉对应的子线程而且返回错误码:Invalid argument
    // sleep(2);
    // int join_ret= pthread_join(tid_1,nullptr);
    // cout<<strerror(join_ret)<<endl;
    // join_ret= pthread_join(tid_2,nullptr);
    // cout<<strerror(join_ret)<<endl;
    // join_ret= pthread_join(tid_3,nullptr);
    // cout<<strerror(join_ret)<<endl;
    //确保主线程最后退出,确保其他线程能将所有任务完成
    //因为主线程代表进程,主线程退出,整个进程退出,进程内的各个资源都会被OS回收
    //包括各执行流,进程地址空间,进程页表,代码,上下文数据...
    //
    //  线程分离的场景:1.不关心子线程的退出情况,不想花时间等待
    //                2.主线程不要退出(常驻内存)或保证了最后退出
    sleep(8);
    cout<<"进程退出"<<endl;
    return 0;
}